package com.xhwl.data.pojo.space;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.xhwl.common.dto.cent.sdata.OrganizationDTO;
import com.xhwl.common.dto.cent.sdata.space.*;
import com.xhwl.common.enums.ImportStatus;
import com.xhwl.common.enums.space.RoomStatusEnum;
import com.xhwl.common.exception.DataException;
import com.xhwl.common.pojo.ResultJson;
import com.xhwl.common.pojo.cent.sdata.Account;
import com.xhwl.common.pojo.cent.sdata.OrganizationType;
import com.xhwl.common.pojo.cent.sdata.Region;
import com.xhwl.common.pojo.cent.sdata.Room;
import com.xhwl.common.pojo.cent.sdata.space.AbstractSpaceExcel;
import com.xhwl.common.pojo.cent.sdata.space.OrganizationImport;
import com.xhwl.common.pojo.msg.NoticeData;
import com.xhwl.common.pojo.msg.Target;
import com.xhwl.common.utils.StringUtils;
import com.xhwl.common.utils.excel.ExcelUtils;
import com.xhwl.data.dao.IRegionDao;
import com.xhwl.data.service.*;
import org.apache.commons.collections4.CollectionUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * @Author: luyi
 * @Description:
 * @Date: Create in 10:46 2023/3/24
 */
@Component
public class SpaceImportHandler {

    private static final Logger log = LoggerFactory.getLogger(SpaceImportHandler.class);

    @Autowired
    RedisTemplate redisTemplate;

    @Autowired
    IOrganizationImportService organizationImportService;

    @Autowired
    IMessageCentService messageCentService;

    @Autowired
    ISpaceExcelImportService spaceExcelImportService;

    @Autowired
    IOrganizationTypeService organizationTypeService;

    @Autowired
    IOrganizationService organizationService;

    @Autowired
    private IRegionDao regionDao;

    static final Integer importSize = 10000;

    private static final Map<String, Class> SPACE_MAP = new HashMap();

    static {
        SPACE_MAP.put("building", BuildingExcelDTO.class);
        SPACE_MAP.put("floor", FloorExcelDTO.class);
        SPACE_MAP.put("room", RoomExcelDTO.class);
        SPACE_MAP.put("area", AreaExcelDTO.class);
        SPACE_MAP.put("public-area", PublicAreaExcelDTO.class);
        SPACE_MAP.put("unit", UnitExcelDTO.class);
        SPACE_MAP.put("block", BlockExcelDTO.class);
        SPACE_MAP.put("balcony", BalconyExcelDTO.class);
    }


    public void emport(MultipartFile file, Integer type, Integer projectId, Account account){
        List result = new ArrayList();
        List<String> fields = new ArrayList<>();
        fields.add("parentName");
        fields.add("parentChainCode");
        OrganizationType organizationType = organizationTypeService.getById(type);
        JSONObject jsonObject = JSONObject.parseObject(organizationType.getSource());
        JSONArray jsonArray = jsonObject.getJSONArray("fields");
        if (jsonArray != null && jsonArray.size() > 0) {
            for (int i = 0; i < jsonArray.size(); i++) {
                fields.add(jsonArray.getJSONObject(i).getString("vModel"));
            }
        }
        List<ErrorSpace> errList = new ArrayList<>();
        Class aClass = SPACE_MAP.get(organizationType.getCode());
        if(null == aClass){
            //List<String> order = (List<String>) jsonObject.get("order");
            //fields.addAll(order);
            List list = ExcelUtils.readExcel(fields, file, 3, 0);
            check(list);
            result.addAll(list);
        }else{
            //Person p=JSON.parseObject(str,Person.class);
            //list = ExcelUtils.readExcel(aClass, file, 3);
            List list = ExcelUtils.readExcel(fields, file, 3, 0);
            check(list);
            if(CollectionUtils.isNotEmpty(list)){
                for (int i = 0; i < list.size(); i++) {
                    JSONObject jsonObject1 = JSON.parseObject(list.get(i).toString());
                    switch (organizationType.getCode()){
                        case "building":
                            try {
                                if(jsonObject1 != null && jsonObject1.get("type") != null && StringUtils.isNotEmpty(jsonObject1.get("type").toString())) {
                                    String typeStr = jsonObject1.get("type").toString();
                                    Short.parseShort(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("类型错误",jsonObject1));
                                break;
                            }
                            BuildingExcelDTO buildingExcelDTO = JSON.parseObject(list.get(i).toString(), BuildingExcelDTO.class);
                            buildingExcelDTO.setExpand(list.get(i).toString());
                            result.add(buildingExcelDTO);
                            break;
                        case "floor":
                            try {
                                if(jsonObject1 != null && jsonObject1.get("type") != null && StringUtils.isNotEmpty(jsonObject1.get("type").toString())) {
                                    String typeStr = jsonObject1.get("type").toString();
                                    Short.parseShort(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("类型错误",jsonObject1));
                                break;
                            }
                            FloorExcelDTO floorExcelDTO = JSON.parseObject(list.get(i).toString(), FloorExcelDTO.class);
                            floorExcelDTO.setExpand(list.get(i).toString());
                            result.add(floorExcelDTO);
                            break;
                        case "room":
                            try {
                                if(jsonObject1 != null && jsonObject1.get("type") != null && StringUtils.isNotEmpty(jsonObject1.get("type").toString())) {
                                    String typeStr = jsonObject1.get("type").toString();
                                    Short.parseShort(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("类型错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("area") != null && StringUtils.isNotEmpty(jsonObject1.get("area").toString())) {
                                    String typeStr = jsonObject1.get("area").toString();
                                    Double.parseDouble(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("建筑面积错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("insideSpace") != null && StringUtils.isNotEmpty(jsonObject1.get("insideSpace").toString())) {
                                    String typeStr = jsonObject1.get("insideSpace").toString();
                                    Double.parseDouble(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("套内面积错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("usableArea") != null && StringUtils.isNotEmpty(jsonObject1.get("usableArea").toString())) {
                                    String typeStr = jsonObject1.get("usableArea").toString();
                                    Double.parseDouble(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("使用面积错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("residentialPoolArea") != null && StringUtils.isNotEmpty(jsonObject1.get("residentialPoolArea").toString())) {
                                    String typeStr = jsonObject1.get("residentialPoolArea").toString();
                                    Double.parseDouble(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("公摊面积错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("status") != null && StringUtils.isNotEmpty(jsonObject1.get("status").toString())) {
                                    String typeStr = jsonObject1.get("status").toString();
                                    RoomStatusEnum roomStatusEnum = RoomStatusEnum.valueOf(typeStr);
                                    jsonObject1.put("status",roomStatusEnum.id);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("状态错误",jsonObject1));
                                break;
                            }
                            RoomExcelDTO roomExcelDTO = JSON.parseObject(jsonObject1.toString(), RoomExcelDTO.class);
                            roomExcelDTO.setExpand(list.get(i).toString());
                            roomExcelDTO.setSortField(i+1);
                            result.add(roomExcelDTO);
                            break;
                        case "area":
                            try {
                                if(jsonObject1 != null && jsonObject1.get("occupiedArea") != null && StringUtils.isNotEmpty(jsonObject1.get("occupiedArea").toString())) {
                                    String typeStr = jsonObject1.get("occupiedArea").toString();
                                    Double.parseDouble(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("占地面积错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("buildingArea") != null && StringUtils.isNotEmpty(jsonObject1.get("buildingArea").toString())) {
                                    String typeStr = jsonObject1.get("buildingArea").toString();
                                    Double.parseDouble(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("建筑面积错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("provinceId") != null && StringUtils.isNotEmpty(jsonObject1.get("provinceId").toString())) {
                                    String typeStr = jsonObject1.get("provinceId").toString();
                                    Short.parseShort(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("省id错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("cityId") != null && StringUtils.isNotEmpty(jsonObject1.get("cityId").toString())) {
                                    String typeStr = jsonObject1.get("cityId").toString();
                                    Short.parseShort(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("市id错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("districtId") != null && StringUtils.isNotEmpty(jsonObject1.get("districtId").toString())) {
                                    String typeStr = jsonObject1.get("districtId").toString();
                                    Short.parseShort(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("区id错误",jsonObject1));
                                break;
                            }
                            //将区域名称转成id
                            String msg = nameChangeId(jsonObject1);
                            if(msg != null){
                                errList.add(getErrorSpace(msg,jsonObject1));
                                break;
                            }
                            AreaExcelDTO areaExcelDTO = JSON.parseObject(jsonObject1.toString(), AreaExcelDTO.class);
                            //areaExcelDTO.setExpand(list.get(i).toString());
                            areaExcelDTO.setExpand(jsonObject1.toString());
                            result.add(areaExcelDTO);
                            break;
                        case "public-area":
                            try {
                                if(jsonObject1 != null && jsonObject1.get("type") != null && StringUtils.isNotEmpty(jsonObject1.get("type").toString())) {
                                    String typeStr = jsonObject1.get("type").toString();
                                    Short.parseShort(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("类型错误",jsonObject1));
                                break;
                            }
                            PublicAreaExcelDTO publicAreaExcelDTO = JSON.parseObject(list.get(i).toString(), PublicAreaExcelDTO.class);
                            publicAreaExcelDTO.setExpand(list.get(i).toString());
                            result.add(publicAreaExcelDTO);
                            break;
                        case "unit":
                            UnitExcelDTO unitExcelDTO = JSON.parseObject(list.get(i).toString(), UnitExcelDTO.class);
                            unitExcelDTO.setExpand(list.get(i).toString());
                            result.add(unitExcelDTO);
                            break;
                        case "block":
                            try {
                                if(jsonObject1 != null && jsonObject1.get("area") != null && StringUtils.isNotEmpty(jsonObject1.get("area").toString())) {
                                    String typeStr = jsonObject1.get("area").toString();
                                    Double.parseDouble(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("建筑面积错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("publicArea") != null && StringUtils.isNotEmpty(jsonObject1.get("publicArea").toString())) {
                                    String typeStr = jsonObject1.get("publicArea").toString();
                                    Double.parseDouble(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("公区面积错误",jsonObject1));
                                break;
                            }
                            try {
                                if(jsonObject1 != null && jsonObject1.get("rentalArea") != null && StringUtils.isNotEmpty(jsonObject1.get("rentalArea").toString())) {
                                    String typeStr = jsonObject1.get("rentalArea").toString();
                                    Double.parseDouble(typeStr);
                                }
                            }catch (Exception ex){
                                errList.add(getErrorSpace("租赁面积错误",jsonObject1));
                                break;
                            }
                            BlockExcelDTO blockExcelDTO = JSON.parseObject(list.get(i).toString(), BlockExcelDTO.class);
                            blockExcelDTO.setExpand(list.get(i).toString());
                            blockExcelDTO.setSortField(i+1);
                            result.add(blockExcelDTO);
                            break;
                        case "balcony":
                            BalconyExcelDTO balconyExcelDTO = JSON.parseObject(list.get(i).toString(), BalconyExcelDTO.class);
                            balconyExcelDTO.setExpand(list.get(i).toString());
                            result.add(balconyExcelDTO);
                            break;
                    }
                }
            }
        }
        int total = result.size()+errList.size();
        OrganizationImport organizationImport = before(file, type, result);
        ResultJson entityToImport =null;
        List<String> strList =Arrays.asList("building","room","floor","area","public-area","unit","balcony","block");
        if(strList.contains(organizationType.getCode())) {
            entityToImport = getEntityToImport(result, organizationTypeService.getById(type), account, projectId);
        }else {
            entityToImport = spaceExcelImportService.batchImportSpace(result, organizationType, account, projectId);
        }
        //处理错误数据
        List<ErrorSpace> resultList = (List<ErrorSpace>)entityToImport.getResult();
        if(CollectionUtils.isNotEmpty(resultList)){
            resultList.addAll(errList);
        }else {
            entityToImport.setResult(errList);
        }
        after(entityToImport, projectId, organizationImport, account, total);
    }

    /**
     * 将区域名专场id
     */
    private String nameChangeId(JSONObject jsonObject){
        if(jsonObject == null && StringUtils.isEmpty(jsonObject.getString("region"))){
            return null;
        }
        String region = jsonObject.getString("region");
        if(region == null || region.equals("") ||region.equals(" ")){
            return null;
        }
        String[] split = region.split("-");
        QueryWrapper<Region> queryWrapper = new QueryWrapper();
        queryWrapper.in("name",Arrays.asList(split));
        List<Region> regions = regionDao.selectList(queryWrapper);
        if(CollectionUtils.isEmpty(regions)){
            return "所在地错误";
        }
        Map<String,Region> map = new HashMap<>();
        Map<String,Region> mapPid = new HashMap<>();
        for(Region vo:regions){
            map.put(vo.getName(),vo);
            mapPid.put(vo.getName()+vo.getPid(),vo);
        }
        List<String> regionNew = new ArrayList<>();
        String parentId = "";
        for (int i = 0; i < split.length; i++) {
            if(i==0){
                if(map.get(split[0])!= null){
                    parentId=map.get(split[0]).getId()+"";
                    regionNew.add(map.get(split[i]).getId()+"");
                }else{
                    return "所在地不存在";
                }
            }else{
                if(mapPid.get(split[i]+parentId)!= null){
                    String id = mapPid.get(split[i]+parentId).getId()+"";;
                    parentId = id;
                    regionNew.add(id);
                }else{
                    return "所在地层级错误";
                }
            }
        }
        return null;
    }

    private ErrorSpace getErrorSpace(String msg,Object obj){
        ErrorSpace errorSpace = new ErrorSpace();
        errorSpace.setReason(msg);
        errorSpace.setObj(obj);
        return errorSpace;
    }

    public <T extends AbstractSpaceExcel> OrganizationImport before(MultipartFile file, Integer type, List<T> excelDTOS){

        OrganizationImport organizationImport = new OrganizationImport();
        check(excelDTOS);
        organizationImport.setStatus(ImportStatus.WORKING);
        organizationImport.setFileName(file.getOriginalFilename());
        organizationImport.setType(type);
        organizationImport.setSize((double) file.getSize() / (1024 * 1024));

        OrganizationType organizationType = organizationTypeService.getById(type);
        if(null == organizationType){
            throw new DataException("空间类型错误");
        }
        organizationImportService.save(organizationImport);
        return organizationImport;
    }

    protected void after(ResultJson<List<ErrorSpace>> listResultJson, Integer projectId, OrganizationImport organizationImport, Account account, int total){
        record(total, listResultJson, projectId, organizationImport, account);
    }

    private void record(int total, ResultJson<List<ErrorSpace>> listResultJson, int projectId, OrganizationImport organizationImport, Account account){

        organizationImport.setStatus(ImportStatus.COMPLETED);
        List<ErrorSpace> result = listResultJson.getResult();
        StringBuilder sbd = new StringBuilder();
        if(CollectionUtils.isEmpty(result)){
            sbd.append("全部成功，共").append(total);
            organizationImport.setIsCompletedSuccess(true);
        }else if(result.size() == total){
            sbd.append("全部失败, 共").append(total);
            organizationImport.setIsCompletedSuccess(false);
            String fileId = UUID.randomUUID().toString().replaceAll("-", "");
            organizationImport.setFileId(fileId);
            redisTemplate.opsForValue().set(fileId, result, 7, TimeUnit.DAYS);
        }else{
            sbd.append("成功").append(total - result.size()).append("，失败").append(result.size()).append("，共").append(total);
            organizationImport.setIsCompletedSuccess(false);
            String fileId = UUID.randomUUID().toString().replaceAll("-", "");
            organizationImport.setFileId(fileId);
            redisTemplate.opsForValue().set(fileId, result, 7, TimeUnit.DAYS);
        }
        organizationImport.setImportResult(sbd.toString());
        organizationImport.setProjectId(projectId);
        organizationImport.setAccountId(account.getId());
        organizationImportService.updateById(organizationImport);

        // 通知用户上传完毕了
        NoticeData noticeData = new NoticeData();
        noticeData.setTitle("UPLOAD_SPACE_FINISHED");
        Map<String, String> map = new HashMap<>();
        map.put("total", String.valueOf(total));
        map.put("fail", String.valueOf(result.size()));
        map.put("fileId", organizationImport.getFileId());
        map.put("typeId", String.valueOf(organizationImport.getType()));
        map.put("recordId", String.valueOf(organizationImport.getId()));
        noticeData.setParams(map);
        // 消息分类
        noticeData.setCategory(Arrays.asList("space_import"));
        log.info("通知用户 {} 记录id {} 已经上传完成了", account.getId(), organizationImport.getId());
        try {
            Target target = new Target();
            target.setReceivers(Arrays.asList(account.getId().toString()));
            ResultJson resultJson = messageCentService.send("websocket", noticeData, target);
            log.info("消息发送结果 {}", JSONObject.toJSONString(resultJson));
        }catch (Exception e){
            log.error("上传完毕，通知用户失败了 {}", e.getMessage());
        }
    }

    protected void check(List spaceExcels){
        if(CollectionUtils.isEmpty(spaceExcels)){
            throw new DataException("空数据");
        }
        if(importSize < spaceExcels.size()){
            throw new DataException("超过数量限制");
        }
    }

    /**
     * 映射具体的导入实体类
     * @param excelDTOS
     * @param organizationType
     * @param account
     * @param <T>
     * @return
     */
    private <T extends AbstractSpaceExcel> ResultJson<List<ErrorSpace>> getEntityToImport(List<T> excelDTOS, OrganizationType organizationType, Account account, Integer projectId){
        //T t = excelDTOS.get(0);
        if("building".equals(organizationType.getCode())){
            return spaceExcelImportService.batchImportBuilding((List<BuildingExcelDTO>) excelDTOS, account, projectId);
        }else if("room".equals(organizationType.getCode())){
            return spaceExcelImportService.batchImportRoom((List<RoomExcelDTO>) excelDTOS, account, projectId);
        }else if("floor".equals(organizationType.getCode())){
            return spaceExcelImportService.batchImportFloor((List<FloorExcelDTO>) excelDTOS, account, projectId);
        }else if("area".equals(organizationType.getCode())){
            return spaceExcelImportService.batchImportArea((List<AreaExcelDTO>) excelDTOS, account, projectId);
        }else if("public-area".equals(organizationType.getCode())){
            return spaceExcelImportService.batchImportPublicArea((List<PublicAreaExcelDTO>) excelDTOS, account, projectId);
        }else if("unit".equals(organizationType.getCode())){
            return spaceExcelImportService.batchImportUnit((List<UnitExcelDTO>) excelDTOS, account, projectId);
        }else if("balcony".equals(organizationType.getCode())){
            return spaceExcelImportService.batchImportBalcony((List<BalconyExcelDTO>) excelDTOS, account, projectId);
        }else if("block".equals(organizationType.getCode())){
            return spaceExcelImportService.batchImportBlock((List<BlockExcelDTO>) excelDTOS, account, projectId);
        }/*else{
            List<JSONObject> jsonObjects = new ArrayList<>(excelDTOS.size());
            for (T excelDTO : excelDTOS) {
                String jsonOjbectStr = JSON.toJSONString(excelDTO);
                jsonObjects.add(JSON.parseObject(jsonOjbectStr));
            }
            List list = (List<BuildingExcelDTO>) excelDTOS;
            return spaceExcelImportService.batchImportSpace(jsonObjects, organizationType, account, projectId);
        }*/
        return ResultJson.success();
    }

}
